/**
 * Copyright ©2003~2019年10月6日 szkingdom
 * @author raohj
 * @date 2019年10月6日
 * @file RClassTest.java
 * @comment : please input your comment to this file
 * @version : input version
 * @modify:
 * 		1、 2019年10月6日 由 raohj 新建文件
 */
package com.ccnu.demojava.jvm.classparse;

import com.ccnu.demojava.util.RConvert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author raohj
 * @date 2019年10月6日
 * @version
 * @comment to add your comment
 */
public class RTest_ClassParse {
	static Logger log = LoggerFactory.getLogger(RTest_ClassParse.class);

	public static void test() {
		RClassStruct rcs = RClassParse.parseClassFile("D:/temp/RClassStander.class");
		printClass(rcs);
	}

	public static void printClassAttr(RCS_cp_info[] cpInfoArray, int index) {
		int i = 0;
		for (; i < cpInfoArray.length; i++) {
			RCS_cp_info cpInfo = cpInfoArray[i];
			// 获取Class对象
			if (cpInfo.getTag() == 9) {
				RCS_cp_info.Constant_Fieldref_Info cfi = (RCS_cp_info.Constant_Fieldref_Info) cpInfo.getInfo();
				if (cfi.class_index == index + 1) {

				}
			}
		}
	}

	public static void printCpInfo(int i, RCS_cp_info cpInfo) {
		if (cpInfo == null) {
			return;
		}
		switch (cpInfo.getTag()) {
		case 1:
			RCS_cp_info.Constant_Utf8_Info cutf8 = (RCS_cp_info.Constant_Utf8_Info) cpInfo.getInfo();
			log.info(i + "|UTF-8|len:" + cutf8.len + "|bytes:" + new String(cutf8.bytes));
			break;
		case 3:
			RCS_cp_info.Constant_Integer_Info ci = (RCS_cp_info.Constant_Integer_Info) cpInfo.getInfo();
			log.info(i + "|Integer|value:" + ci.value);
			break;
		case 4:
			RCS_cp_info.Constant_Float_Info cfloat = (RCS_cp_info.Constant_Float_Info) cpInfo.getInfo();
			log.info(i + "|Float|value:" + cfloat.value);
			break;
		case 5:
			RCS_cp_info.Constant_Long_Info cl = (RCS_cp_info.Constant_Long_Info) cpInfo.getInfo();
			log.info(i + "|Long|value:" + cl.value);
			break;
		case 6:
			RCS_cp_info.Constant_Double_Info cd = (RCS_cp_info.Constant_Double_Info) cpInfo.getInfo();
			log.info(i + "|Double|value:" + cd.value);
			break;
		case 7: // ConstantClassInfo
			RCS_cp_info.Constant_Class_Info cc = (RCS_cp_info.Constant_Class_Info) cpInfo.getInfo();
			log.info(i + "|Class|name_index:" + cc.name_index);
			break;
		case 8:
			RCS_cp_info.Constant_String_Info cs = (RCS_cp_info.Constant_String_Info) cpInfo.getInfo();
			log.info(i + "|String|name_index:" + cs.string_index);
			break;
		case 9:
			RCS_cp_info.Constant_Fieldref_Info cf = (RCS_cp_info.Constant_Fieldref_Info) cpInfo.getInfo();
			log.info(i + "|Fieldref|class_index:" + cf.class_index + "|name_and_type_index:" + cf.name_and_type_index);
			break;
		case 10:
			RCS_cp_info.Constant_Methodref_Info cm = (RCS_cp_info.Constant_Methodref_Info) cpInfo.getInfo();
			log.info(i + "|Fieldref|class_index:" + cm.class_index + "|name_and_type_index:" + cm.name_and_type_index);
			break;
		case 11:
			RCS_cp_info.Constant_InterfaceMethodref_Info cim = (RCS_cp_info.Constant_InterfaceMethodref_Info) cpInfo
					.getInfo();
			log.info(
					i + "|Fieldref|class_index:" + cim.class_index + "|name_and_type_index:" + cim.name_and_type_index);
			break;
		case 12:
			RCS_cp_info.Constant_NameAndType_Info cnt = (RCS_cp_info.Constant_NameAndType_Info) cpInfo.getInfo();
			log.info(i + "|NameAndType|name_index:" + cnt.name_index + "|descriptor_index:" + cnt.descriptor_index);
			break;
		case 15:
			RCS_cp_info.Constant_MethodHandle_Info cmh = (RCS_cp_info.Constant_MethodHandle_Info) cpInfo.getInfo();
			log.info(i + "|MethodHandle|reference_kind:" + cmh.reference_kind + "|reference_index:"
					+ cmh.reference_index);
			break;
		case 16:
			RCS_cp_info.Constant_MethodType_Info cmt = (RCS_cp_info.Constant_MethodType_Info) cpInfo.getInfo();
			log.info(i + "|MethodType|descriptor_index:" + cmt.descriptor_index);
			break;
		case 18:
			RCS_cp_info.Constant_InvokeDynamic_Info cii = (RCS_cp_info.Constant_InvokeDynamic_Info) cpInfo.getInfo();
			log.info(i + "|InvokeDynamic|bootstrap_method_attr_index:" + cii.bootstrap_method_attr_index
					+ "|name_and_type_index:" + cii.name_and_type_index);
			break;
		default:
			log.info(i + "|不支持的类型" + cpInfo.getTag());
			break;
		}
	}

	private static String getConstantUtf8(RClassStruct cs, int name_index) {
		RCS_cp_info.Constant_Utf8_Info cutf8 = (RCS_cp_info.Constant_Utf8_Info) cs.constant_pool[name_index].getInfo();
		return new String(cutf8.bytes);
	}

	/**
	 * @author raohj
	 * @date 2019年10月6日
	 * @comment 打印jdk的版本add your comment
	 * @param
	 * @return
	 * @param cs
	 */
	public static void printJDKVersion(RClassStruct cs) {
		if (cs.major_version < 48 && cs.major_version >= 45) {
			log.info("JDK版本: 1." + (cs.major_version - 44));
		} else {
			log.info("JDK版本: " + (cs.major_version - 44));
		}
	}

	/**
	 * @author raohj
	 * @date 2019年4月3日
	 * @comment 获取Class对象
	 * @param
	 * @return
	 */
	public static void printClass(RClassStruct cs) {
		log.info("==============打印JDK版本信息==================");
		printJDKVersion(cs);
		log.info("==============打印类信息==================");
		printThisClass(cs);
		printSuperClass(cs);
		printInterface(cs);
		log.info("==============打印const信息==================");
		printConst(cs);
		log.info("==============打印fields信息==================");
		printField(cs);
		log.info("==============打印methods信息==================");
		printMethod(cs);
		log.info("==============打印Attributes信息==================");
		printAttributes(cs);
	}

	public static void printConst(RClassStruct cs) {
		int i = 0;
		for (; i < cs.constant_pool.length; i++) {
			RCS_cp_info cpInfo = cs.constant_pool[i];
			printCpInfo(i, cpInfo);
		}
	}

	public static void printThisClass(RClassStruct cs) {
		RCS_cp_info.Constant_Class_Info cci = (RCS_cp_info.Constant_Class_Info) cs.constant_pool[cs.this_class - 1]
				.getInfo();
		log.info("类名称:" + getConstantUtf8(cs, cci.name_index - 1));
	}

	public static void printSuperClass(RClassStruct cs) {
		if (cs.super_class > 0) {
			RCS_cp_info.Constant_Class_Info cci = (RCS_cp_info.Constant_Class_Info) cs.constant_pool[cs.super_class - 1]
					.getInfo();
			log.info("父类名称:" + getConstantUtf8(cs, cci.name_index - 1));
		}
	}

	public static void printInterface(RClassStruct cs) {
		for (int i = 0; i < cs.interface_count; i++) {
			RCS_cp_info.Constant_Class_Info cci = (RCS_cp_info.Constant_Class_Info) cs.constant_pool[cs.interfaces[i]
					- 1].getInfo();
			log.info("接口" + i + "[" + getConstantUtf8(cs, cci.name_index - 1) + "]");
		}
	}

	public static void printField(RClassStruct cs) {
		int i = 0;
		for (; i < cs.fields.length; i++) {
			StringBuilder sb = new StringBuilder("");
			RCS_field_info fieldInfo = cs.fields[i];
			{
				// 获取属性
				if ((fieldInfo.access_flag & RClass_Constant.ACC_PUBLIC) > 0) {
					sb.append("public ");
				} else if ((fieldInfo.access_flag & RClass_Constant.ACC_PRIVATE) > 0) {
					sb.append("private ");
				} else if ((fieldInfo.access_flag & RClass_Constant.ACC_PROTECTED) > 0) {
					sb.append("protected ");
				}

				if ((fieldInfo.access_flag & RClass_Constant.ACC_STATIC) > 0) {
					sb.append("static ");
				}

				if ((fieldInfo.access_flag & RClass_Constant.ACC_FINAL) > 0) {
					sb.append("final ");
				}

				if ((fieldInfo.access_flag & RClass_Constant.ACC_VOLATILE) > 0) {
					sb.append("volatile ");
				}

				if ((fieldInfo.access_flag & RClass_Constant.ACC_TRANSIENT) > 0) {
					sb.append("transient ");
				}

				if ((fieldInfo.access_flag & RClass_Constant.ACC_SYNTHETIC) > 0) {
					sb.append("synthetic ");
				}

				if ((fieldInfo.access_flag & RClass_Constant.ACC_ENUM) > 0) {
					sb.append("enum ");
				}
			}

			{
				// 获取类型
				String defType = getConstantUtf8(cs, fieldInfo.descriptor_index - 1);
				StringBuilder arrayCnt = new StringBuilder("");
				// 判断是否是数组
				if (defType.length() > 1 && defType.getBytes()[0] == '[') {
					int j = 0;
					for (; j < defType.length() - 1; j++) {
						if (defType.getBytes()[j] == '[') {
							arrayCnt.append("[]");
						} else {
							break;
						}
					}
					defType = defType.substring(j);
				}
				if (defType.length() > 1 && defType.getBytes()[0] == 'L') {
					defType = defType.substring(1);
					defType = defType.replaceAll("/", ".");
					defType = defType.replaceAll(";", "");
				}
				// 非数组再进行处理
				if (defType.length() == 1) {
					if (defType.equals("I")) {
						defType = "int";
					} else if (defType.equals("S")) {
						defType = "short";
					} else if (defType.equals("B")) {
						defType = "byte";
					} else if (defType.equals("F")) {
						defType = "float";
					} else if (defType.equals("D")) {
						defType = "double";
					} else if (defType.equals("J")) {
						defType = "long";
					} else if (defType.equals("C")) {
						defType = "char";
					} else if (defType.equals("Z")) {
						defType = "boolean";
					}
				}
				sb.append(defType + arrayCnt + " ");
			}
			sb.append(getConstantUtf8(cs, fieldInfo.name_index - 1));
			log.info("字段:" + sb);
		}
	}

	public static void printMethod(RClassStruct cs) {
		int i = 0;
		for (; i < cs.methods.length; i++) {
			StringBuilder sb = new StringBuilder("");
			RCS_method_info methodInfo = cs.methods[i];
			// 获取类型
			String defType = getConstantUtf8(cs, methodInfo.descriptor_index - 1);
			sb.append(defType);
			sb.append(getConstantUtf8(cs, methodInfo.name_index - 1));
			log.info("方法:" + sb);
		}
	}

	public static void printAttributes(RClassStruct cs) {
		for (int i = 0; i < cs.attributes_count; i++) {
			RCS_attribute_info attributeInfo = cs.attributes[i];
			StringBuilder appendInfo = new StringBuilder("");
			String attr_name = getConstantUtf8(cs, attributeInfo.attr_name_index - 1);
			if (attr_name.equals("SourceFile")) {
				appendInfo.append(getConstantUtf8(cs, RConvert.bytesToShort(attributeInfo.info) - 1));
			}
			log.info("属性:[" + attr_name + "]值:" + appendInfo);
		}
	}
}
